#include "CasilleroA.h"

CasilleroA::~CasilleroA() {
    free(info);
}

CasilleroA::CasilleroA(const CasilleroA& Origen) : Casillero(Origen.dimenciones, Origen.posVacio) {
    info = (char*) malloc(((dimenciones * dimenciones) / 2) * sizeof (char));
    memcpy(info, Origen.info, (dimenciones * dimenciones) / 2 * sizeof (char));
}

CasilleroA::CasilleroA(const int *informacion, int dimenciones, short posicionDeVacio) : Casillero(dimenciones, posicionDeVacio) {

    int posChar, subpack;
    int tam = (dimenciones * dimenciones) / 2;
    if (informacion == NULL)
        throw new Excepcion("info no debe ser NULL en \"Casillero::Casillero(int *info, int dimenciones)\".");

    if (informacion[posVacio] != 0)
        throw new Excepcion("Arreglo info no contiene cero en posicion de vacio en \"Casillero::Casillero(int *info, int dimenciones)\".");


    this->info = (char*) calloc(tam, 1);
    //construir el arreglo de chars
    {
        char elem = 0x00;
        int valor;
        for (int i = 0; i < dimenciones * dimenciones; i++) {
            valor = informacion[i];
            posChar = i / 2; //posicion del char
            subpack = i % 2; //pos del paquete
            if (subpack == 0) {
                elem = valor;
                elem <<= 4;
            } else {
                elem |= valor;
                info[posChar] = elem;
                elem = 0x00;
            }
        }
    }
}

char CasilleroA::Info(int i) const {
    char valor;
    char packet = i / 2;
    char subpacket = i % 2;
    valor = info[packet];
    switch (subpacket) {
        case 0: //Subpaquete de 4 bits mas significativos
            valor >>= 4;
            valor &= 0x0F;
            break;
        case 1: //Subpaquete de 4 bit menos significativos
            valor &= 0x0F;
            break;
    }
    return valor;
}


//pos representa la posicion a donde quiero mover el blanco

void CasilleroA::moverCero(int pos) {
    if (pos >= dimenciones * dimenciones || pos < 0)
        throw new Excepcion("parametro pos fuera de los limites en \"void Casillero::moverCero(int pos)\"");
    int posCero = posVacio / 2;
    int subpackCero = posVacio % 2;
    posVacio = (short) pos;

    int posChar;
    posChar = pos / 2;
    int adentro = pos % 2;
    char val = info[posChar];

    if (adentro == 0) {
        //es el primer char
        info[posChar] = 0x0F & val;
        val = val >> 4;
        val &= 0x0F;
    } else {
        //es el segundo subChar donde tengo que poner el 0
        info[posChar] = 0xF0 & val;
        val = 0x0F & val;
    }
    if (subpackCero == 0) {

        val = val << 4;
        info[posCero] = (0x0F & info[posCero]) | val;
    } else {

        info[posCero] = (0xF0 & info[posCero]) | val;
    }
}

short CasilleroA::Dimenciones() const {
    return dimenciones;
}

short CasilleroA::Vacio() const {
    return posVacio;
}

Casillero* CasilleroA::Clone() const {
    int info[dimenciones * dimenciones];
    for (int i = 0; i < dimenciones * dimenciones; i++) {
        info[i] = Info(i);
    }
    return new CasilleroA(info, dimenciones, posVacio);
}

void CasilleroA::toString(char *out) const {
    int i, j, k = 0;
    for (i = 0; i < dimenciones; i++) {
        for (j = 0; j < dimenciones; j++) {
            if (Info(k) < 10) sprintf(out++, " ");

            sprintf(out++, "%d", Info(k++));
            if (Info(k - 1) >= 10) out++;

            if (j < dimenciones - 1) {
                sprintf(out, ", ");
                out += 2;
            }
        }
        if (i < dimenciones - 1) sprintf(out++, "\n");
    }
}

/**
 * Retorna una representacion del casillero en String.
 * @return Un string alojado en memoria con la representacion del Casillero.
 */
char* CasilleroA::toString() const {
    int size = (4 * dimenciones * dimenciones - dimenciones + 1);
    char * r = (char *) malloc((size + 1) * sizeof (char));
    toString(r);
    r[size] = '\0';
    return r;
}

const char * CasilleroA::getInfo() const {
    return info;
}

bool CasilleroA::operator==(const CasilleroA &c) const {
    return !(memcmp(this->getInfo(), c.getInfo(), 8));
}

void CasilleroA::print(ostream& stream) const {
    char* output = CasilleroA::toString();
    stream << output;
    stream << "\n";
    free(output);
}



